The present invention relates generally to the field of computer software and software portability. In particular, it relates to methods of compiling a program according to platform-specific requirements.
The Java.TM. virtual machine (JVM) can be implemented on a variety of different computer architectures and can accommodate different specifications and standards stemming from different microprocessors. An example of such a standard is the extended precision floating point format utilized by some microprocessors when manipulating floating point numbers. One such microprocessor is Intel Corporation's IA-32 microprocessor architecture which uses the extended precision (80 bit) floating point calculations. Other processors typically use single (32 bit) or double (64 bit) precision floating point calculations.
A problem occurs when values computed in extended precision format are converted to single or double precision format. The example problem arises because the Java.TM. language specifies that floating point operations must produce results with the range and precision specified by IEEE 754, incorporated herein by reference for all purposes, whereas the Intel IA-32 processors, made by the Intel Corporation of Santa Clara, Calif., produce results with greater range and precision. These wider results must be accurately rounded to IEEE 754 single and double precision format. On the IA-32 microprocessor there are at least two ways to implement such rounding, each with different costs (code size and execution speed). A static compiler (or a one-time dynamic compiler) needs to choose one implementation, and that choice will not be the best choice in all circumstances. The problem is illustrated in FIG. 1.
FIG. 1 is a block diagram describing a typical format of double precision floating point and the format of extended precision floating point. Format 102 illustrates an extended precision floating point number format of the Intel IA-32 architecture, as opposed to double precision floating point format of the Intel IA-32. A sign bit 104 indicates whether the number is positive or negative. This is followed by bits 106 which represent an exponent value for representing an exponential value of the floating point is number.
Bits 108 contain bits for holding a significand. The significand portion can hold up to 64 bits for representing the integer portion of the number.
Thus, there are 80 (1+15+64) bits in the extended precision floating point format. Floating point operations are typically handled by a floating point unit. This unit can efficiently perform complicated operations involving floating point numbers by manipulating the significand and the exponent. As is well known in the art, representing floating point numbers as integers and exponents make calculations on floating point numbers significantly easier. Also referred to in FIG. 1 is a double precision floating point format 112, described in IEEE 754. This format is similar in layout to that of the extended precision format, but differs in the number of bits in the exponent and significand fields. As mentioned above, the Intel IA-32 processor produces results in extended format. The example problem comes from the The Java.TM. Language Specification by James Gosling, Bill Joy, and Guy Steele (ISBN 0-201-63451-1), which is incorporated herein by reference in its entirety, in which results need to be produced in IEEE 754 single or double format. Returning to format 112, sign bit 104 is the same as in the extended format, as opposed to double or single precision format. Exponent bits 114 have the same function as bits 106 but holds 11 bits as opposed to 15 bits in the extended format. Significand bits 116 holds 52 bits as opposed to 64 bits in the extended format. Thus, the double precision floating point format can hold 64 bits. The difference in the significand lengths is referred to by the dashed area 118 in FIG. 1 (the 4 bit difference in exponent length is not illustrated similarly in the figure).
Problems arise from the Java language requiring a single or double format result when given an extended precision result from an IA-32 processor, for example. If the extended exponent is outside the range of single or double precision, overflow or underflow will occur. On the IA-32, overflow is handled by the hardware, but can be addressed by methods described in the present invention. Underflow is more difficult to treat since the significand can be shifted (to the right) to reduce the exponent. However, this shifting loses bits of the significand, and therefore precision of the result. Computing the correct, less-precise, significand requires several instructions, and the operation is typically put in a separate subroutine to be invoked when needed. The example problem is not the correct rounding of the result, but the detection that the correction should occur.
FIGS. 2a and 2b illustrate two methods of detecting floating point underflow. In one method, referred to in FIG. 2a, program code 202 detects the problem by performing a trap using a trap handler 204 in the program code to call a trap routine 206, which corrects the problem. In another method, referred to in FIG. 2b, program code 208 includes code 210 for detecting the problem whenever floating points are used in a manner where the problem can potentially arise, such as with multiplication and division operations.
By utilizing trap handler 206, all operations will cease while the problem is being addressed. When a trap is invoked, the state of the machine is stored before executing the trap routine, including the location of the instruction causing the trap. However, if the trap is not invoked, there is no per-operation overhead, only a one-time overhead per thread for setting up the trap handler, that will then monitor all floating point operations. On the other hand, program code 210 shows a technique of inserting code in the program to handle floating point underflow problems. With this method, each operation that might cause an underflow problem is followed by inline code to check for the problem and invoke a subroutine, if necessary, to produce the correctly rounded result. This method requires many unnecessary processor operations for each underflow that does not occur. However, when the problem is detected, it is solved without having to temporarily stop all operations and having to save a process or thread context to handle a trap. As mentioned above, floating point underflow is one example of a problem having alternative solutions on a given platform. Other problems can occur in which several implementations for solving a particular problem are available to the Java virtual machine, with each implementation being more efficient in some cases.
Therefore, it would be desirable to choose intelligently and dynamically an implementation to use in solving a problem arising from platform-specific variations. Using the floating point underflow problem as only an illustration, it would be desirable, for example, to detect and correct floating point underflow while reducing the amount of inline code necessary and avoiding the overhead of using a trap handler to dispatch a subroutine to correct the problem. It would also be desirable to allow a dynamic runtime compiler to choose one implementation, and also monitor its efficiency and change its implementation if desired.